package com.xue.geo;

import com.xue.UdpConnect;
import com.xue.domain.*;
import com.xue.geo.area.AreaJudge;
import com.xue.geo.area.CircularAreaJudge;
import com.xue.geo.area.SquareAreaJudge;
import com.xue.geo.area.TriangleAreaJudge;
import com.xue.geo.domain.Coordinate;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 区域控制器
 *
 * @author xue
 * @create 2022-09-16 17:31
 */
@Slf4j
public class AreaControl {

    private AreaControl() {
    }

    private static class AreaControlHolder {
        private static final AreaControl INSTANCE = new AreaControl();
    }

    public static AreaControl getInstance() {
        return AreaControl.AreaControlHolder.INSTANCE;
    }

    /**
     * 存储各个区域的标识部分
     */
    private static Map<Integer, AreaJudge> areaJudgeMap = new HashMap<>();

    static {
        areaJudgeMap.put(107, new CircularAreaJudge());
        areaJudgeMap.put(108, new TriangleAreaJudge());
        areaJudgeMap.put(101, new SquareAreaJudge());
    }

    /**
     * 记录传递的区域信息
     */
    private final AtomicReference<AreaInfo> bashAtomicReference = new AtomicReference<>(null);

    /**
     * 记录唯一的区域判断信息
     */
    private final AtomicReference<AreaJudge> judgeAtomicReference = new AtomicReference<>(null);

    /**
     * 收到areaInfo信息进行区域改变
     *
     * @param areaInfo
     */
    public void changeArea(AreaInfo areaInfo) {
        // 如果stationId为0的话，则清空区域判断
        if (areaInfo.getStationId() == 0) {
            log.info("stationId为0，关闭区域判断,并关闭所有静态小车灯光");
            judgeAtomicReference.set(null);
            if (staticPoint != null) {
                List<LocationLightInfo> list = staticPoint.stream()
                        .map(item -> new LocationLightInfo(item.getId(), 2)).collect(Collectors.toList());
                UdpConnect.sendInfo(new StaticLocationLightInfo(list));
            }
            return;
        }
        AreaInfo areaBaseTemp = bashAtomicReference.get();
        if (!areaInfo.equals(areaBaseTemp)) {
            AreaJudge areaJudgeTemp = areaJudgeMap.get(areaInfo.getStationId());
            AreaJudge areaJudge = areaJudgeTemp.createArea(areaInfo);
            judgeAtomicReference.set(areaJudge);
            log.info("区域变动，重新判断所有静态点坐标");
            checkStaticPoint(areaJudge);
        }
    }

    /**
     * 判断位置获取区域信息
     *
     * @return
     */
    public AreaJudge getAreaJudge() {
        return judgeAtomicReference.get();
    }

    /**
     * 静态坐标集合
     */
    private static List<LocationInfo> staticPoint;

    /**
     * 当静态信息点提供后执行的方法
     *
     * @param list
     */
    public void receivedStaticPoint(List<LocationInfo> list) {
        staticPoint = list;
        AreaJudge areaJudge = judgeAtomicReference.get();
        if (areaJudge != null) {
            checkStaticPoint(areaJudge);
        }
    }

    private void checkStaticPoint(AreaJudge areaJudge) {
        log.info("进入静态点判断方法");
        if (staticPoint == null) {
            // 请求获取静态点的位置坐标信息
            log.info("静态点坐标为null，尝试获取静态点坐标");
            UdpConnect.sendInfo(new StaticLocationRequestInfo());
            return;
        }
        List<LocationLightInfo> list = staticPoint.stream().map(item -> {
            Boolean inside = areaJudge.pointInside(new Coordinate(item.getCoordinateX(), item.getCoordinateY()));
            return new LocationLightInfo(item.getId(), inside ? 1 : 2);
        }).collect(Collectors.toList());
        UdpConnect.sendInfo(new StaticLocationLightInfo(list));
    }


}
